package com.hawk.eye.framework.config;

import cn.hutool.core.io.resource.ClassPathResource;
import com.hawk.eye.framework.config.properties.HawkEyeServerProperties;
import lombok.AllArgsConstructor;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.jdbc.ScriptRunner;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.context.annotation.Configuration;

import javax.annotation.PostConstruct;
import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.net.URI;
import java.net.URISyntaxException;
import java.nio.charset.StandardCharsets;
import java.sql.*;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 用于第一次启动时，初始化数据库
 *
 * @author zd
 */
@Slf4j
@Configuration
@RequiredArgsConstructor
public class TablesInitConfiguration {
    /**
     * 读取连接地址
     */
    @Value("${spring.datasource.druid.master.url}")
    private String url;
    /**
     * 读取用户名
     */
    @Value("${spring.datasource.druid.master.username}")
    private String username;
    /**
     * 读取密码
     */
    @Value("${spring.datasource.druid.master.password}")
    private String password;

    private final HawkEyeServerProperties properties;

    /**
     * 执行SQL脚本
     *
     * @param path        SQL脚本文件的路径
     * @param isClasspath SQL脚本路径是否是classpath路径
     * @param connection  数据库连接对象，通过这个连接执行脚本
     */
    private void runSQLScript(String path, boolean isClasspath, Connection connection) {
        try (InputStream sqlFileStream = true ? new ClassPathResource(path).getStream() : new FileInputStream(path)) {
            BufferedReader sqlFileStreamReader = new BufferedReader(new InputStreamReader(sqlFileStream, StandardCharsets.UTF_8));
            // 创建SQL脚本执行器对象
            ScriptRunner scriptRunner = new ScriptRunner(connection);
            // 使用SQL脚本执行器对象执行脚本
            scriptRunner.runScript(sqlFileStreamReader);
            // 最后关闭文件读取器
            sqlFileStreamReader.close();
        } catch (Exception e) {
            log.error("读取文件或者执行脚本失败！");
            e.printStackTrace();
        }
    }

    /**
     *
     */
    private boolean currentTablesExists() {
        Connection connection = null;
        Statement statement = null;
        try {
            URI databaseURI = new URI(url.replace("jdbc:", ""));
            // 得到连接地址中的数据库平台名（例如mysql）
            String databasePlatform = databaseURI.getScheme();
            // 得到连接地址和端口
            String hostAndPort = databaseURI.getAuthority();
            // 得到连接地址中的库名
            String databaseName = databaseURI.getPath().substring(1);
            // 组装新的连接URL，不连接至指定库
            String newURL = "jdbc:" + databasePlatform + "://" + hostAndPort + "/";
            // 重新建立连接
            connection = DriverManager.getConnection(newURL, username, password);
            statement = connection.createStatement();
            // 执行SQL语句创建数据库
            String tables = Stream.of(SqlConstant.TABLE_LIST).map(e -> "'" + e + "'").collect(Collectors.joining(","));
            ResultSet resultSet = statement.executeQuery("select COUNT(*) tableCount from INFORMATION_SCHEMA.TABLES " +
                    "where TABLE_SCHEMA='" + databaseName + "' and TABLE_NAME IN (" + tables + ")");
            return resultSet.next() && resultSet.getLong("tableCount") == SqlConstant.TABLE_LIST.length;
        } catch (URISyntaxException e) {
            log.error("数据库连接URL格式错误！");
            throw new RuntimeException(e);
        } catch (SQLException e) {
            log.error("连接失败！");
            throw new RuntimeException(e);
        } finally {
            // 关闭会话和连接
            try {
                if (statement != null) {
                    statement.close();
                }
                if (connection != null) {
                    connection.close();
                }
            } catch (SQLException throwables) {
                throwables.printStackTrace();
            }
        }
    }

    /**
     * 该方法用于检测数据库是否需要初始化，如果是则执行SQL脚本进行初始化操作
     */
    @PostConstruct
    private void initDatabase() {
        if (!properties.getInitTables()) {
            return;
        }
        log.info("开始检查数据库表是否需要初始化...");
        if (currentTablesExists()) {
            log.info("无需初始化数据库表...");
            return;
        }
        // 然后再次连接，执行脚本初始化库中的表格
        try (Connection connection = DriverManager.getConnection(url, username, password)) {
            runSQLScript("/hawk-eye.sql", true, connection);
            log.info("初始化表格完成！");
        } catch (Exception e) {
            log.error("初始化表格时，连接数据库失败！");
            e.printStackTrace();
        }
    }

    interface SqlConstant {
        String[] TABLE_LIST = {"hawk_eye_alarm_base_log", "hawk_eye_alarm_detail_log",
                "hawk_eye_dict_data", "hawk_eye_group", "hawk_eye_outer_service_webhook", "hawk_eye_outer_webhook",
                "hawk_eye_problem_record", "hawk_eye_repair_api", "hawk_eye_repair_log", "hawk_eye_repair_to_problem",
                "hawk_eye_repair_work_order", "hawk_eye_service_config", "hawk_eye_template", "hawk_eye_white_list",
                "hawk_eye_sys_config", "hawk_eye_sys_dept", "hawk_eye_sys_dict_data", "hawk_eye_sys_dict_type", "hawk_eye_sys_logininfor", "hawk_eye_sys_menu", "hawk_eye_sys_oper_log",
                "hawk_eye_sys_post", "hawk_eye_sys_role", "hawk_eye_sys_role_dept", "hawk_eye_sys_role_menu", "hawk_eye_sys_user", "hawk_eye_sys_user_post", "hawk_eye_sys_user_role"};
    }

}